﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Practices.Unity;
using Infrastucture;
using Infrastucture.Collections;
using TimeSplicerModule.Factories;
using TimeSplicerModule.DomainModels;
using TimeSplicerModule.Security;
using TimeSplicerModule.ViewModels;

namespace TimeSplicerModule.Services
{
    public interface ICategoryService
    {
        CategoryViewModel CreateNew();
        CategoryViewModel Get(Guid categoryGuid);
        CategoryViewModel Save(CategoryViewModel model);
        CategoryListViewModel GetListViewModel();
        List<CategoryModel> GetSelectableCategories();
        List<CategoryModel> GetSelectableProjectCategories();
    }

    public class CategoryService : ICategoryService
    {
        private readonly IUnityContainer _container;
        private ISession _session;
        private ITeamService _teamService;
        private ICategoryFactory _categoryFactory;
        private ITeamCategoryFactory _teamCategoryFactory;

        public CategoryService(IUnityContainer container, ICategoryFactory categoryFactory, 
            ITeamService teamService, ITeamCategoryFactory teamCategoryFactory)
        {
            _container = container;
            _categoryFactory = categoryFactory;
            _teamService = teamService;
            _teamCategoryFactory = teamCategoryFactory;
        }


        public CategoryViewModel CreateNew()
        {
            _session = _container.Resolve<ISession>();

            var category = _categoryFactory.CreateNew();
            category.TeamCategories = new List<TeamCategoryModel>();
            category.IsActive = true;

            var teams = _teamService.GetViewableTeams();

            if (_session.User.ApplicationRole.Hierarchy <= 1)
            {
                category.IsGlobal = false;

                // assign to team
                var team = _session.User.Team;

                category.TeamCategories.Add(new TeamCategoryModel
                {
                    TeamGuid = team.TeamGuid,
                    Team = team
                });

                category.Categories = GetSelectableCategories();
                
                // todo: create the category default to the users team
                // can get all teams for the 

                var model = ModelConverter.ToModel<CategoryViewModel>(category);
                model.Teams = teams;
                model.ObservableTeamCategories = model.TeamCategories.ToObservableCollection();
                model.IsGlobalVisibility = System.Windows.Visibility.Visible;

                return model;
            }
            else
            {
                // assign to team
                var team = _session.User.Team;

                category.TeamCategories.Add(new TeamCategoryModel
                    {
                        TeamGuid = team.TeamGuid,
                        Team = team
                    });

                category.Categories = GetSelectableCategories();

                // todo: make is global invisible

                var model = ModelConverter.ToModel<CategoryViewModel>(category);
                model.Teams = teams;
                model.ObservableTeamCategories = model.TeamCategories.ToObservableCollection();
                model.IsGlobalVisibility = System.Windows.Visibility.Collapsed;


                return model;
            }
        }

        public CategoryViewModel Get(Guid categoryGuid)
        {
            _session = _container.Resolve<ISession>();

            var category = _categoryFactory.Get(x => x.CategoryGuid == categoryGuid);
            category.Categories = GetSelectableCategories();

            var all = _categoryFactory.GetList();
            var teams = _teamService.GetViewableTeams();

            category.TeamCategories = _teamCategoryFactory.GetList(x => x.TeamGuid == _session.User.TeamGuid
                && x.CategoryGuid == categoryGuid, all, teams);
            category.ObservableTeamCategories = category.TeamCategories.ToObservableCollection();


            var model = ModelConverter.ToModel<CategoryViewModel>(category);
            model.Teams = teams;

            return model;
        }

        public CategoryViewModel Save(CategoryViewModel model)
        {
            _session = _container.Resolve<ISession>();

            var teamCategories = model.TeamCategories;

            // todo:
            var category = ModelConverter.ToModel<CategoryModel>(model);
            category = _categoryFactory.Upsert(category);

            // TODO: save each team categories
            // need to go and put in a unique constriant
            foreach (var t in teamCategories)
            {
                t.CategoryGuid = category.CategoryGuid;
                _teamCategoryFactory.Upsert(t);
            }


            return Get(category.CategoryGuid);
        }

        public CategoryListViewModel GetListViewModel()
        {
            _session = _container.Resolve<ISession>();

            CategoryListViewModel model = new CategoryListViewModel();
           
            // get selectable
            model.Categories = GetSelectableCategories();

            var all = _categoryFactory.GetList();

            foreach (var c in model.Categories)
            {
                c.ParentCategory = all.FirstOrDefault(x => x.CategoryGuid == c.ParentCategoryGuid);
            }

            return model;
        }

        public List<CategoryModel> GetSelectableCategories()
        {
            _session = _container.Resolve<ISession>();

            // get team and gloabl categories

            // not working?

            // get categories that have this users team
            List<CategoryModel> categories = new List<CategoryModel>();

            var teamCategories = _teamCategoryFactory.GetList(x => x.TeamGuid == _session.User.TeamGuid);
            var all = _categoryFactory.GetList();

            foreach (var c in all)
            {
                var exists = teamCategories.FirstOrDefault(x => x.CategoryGuid == c.CategoryGuid);
                if (c.IsGlobal || exists != null)
                {
                    categories.Add(c);
                    c.TeamCategories = teamCategories.Where(x => x.CategoryGuid == c.CategoryGuid).ToList();
                }
            }

            foreach (var c in categories)
                c.Categories = categories.ToList();


            return categories;
        }

        public List<CategoryModel> GetSelectableProjectCategories()
        {
            var categories = GetSelectableCategories();

            return categories.Where(x => x.IsProjectCategory && x.IsActive).ToList();
        }
    }
}
